﻿//#define START_AND_READ_BY_BARCODE  //由条码来启动和读取数据

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;

namespace Demo
{
    public partial class frmMain : Form
    {
        public enum MMF_EVENT_ID : int
        {
            ERROR = -1,
            GEN_CONCLUSION = 0,
            BAR_CHECK = 1,
            BAR_LENGTH = 2,
            BAR_DOWNLOAD = 3,
            PAR_ACCEPTED = 4,
            MSG_RECEIVED = 5,
            BAT_NOT_REMOVED = 6,
            BAT_REMOVED = 7,
            SCREEN_CLEARED = 8,
        }

        private const int CHANNEL_MAX = 2;

        #region frmMain

        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            #region ItemDictionary初始化

            ItemDictionary.Add("N02", "设备编号");
            ItemDictionary.Add("N0C", "设备固件");
            ItemDictionary.Add("N0D", "产品型号");
            ItemDictionary.Add("N05", "环境温度");
            ItemDictionary.Add("N00", "是否通过");
            ItemDictionary.Add("N0A", "错误代码");
            ItemDictionary.Add("N0F", "花费时间");
            ItemDictionary.Add("N13", "电芯条码");
            ItemDictionary.Add("N03", "电池条码");
            ItemDictionary.Add("N14", "探针剩余");
            ItemDictionary.Add("F00", "条码判定");
            ItemDictionary.Add("N16", "数据文件");

            ItemDictionary.Add("D00", "开路电压1(V)");
            ItemDictionary.Add("D30", "CELL电压(V)");
            ItemDictionary.Add("D31", "CELL-PACK(V)");
            ItemDictionary.Add("D2B", "K值(mV/h)");

            ItemDictionary.Add("D02", "交流阻抗(mΩ)");

            ItemDictionary.Add("D03", "R1(KΩ)");
            ItemDictionary.Add("D04", "R1(℃)");

            ItemDictionary.Add("D05", "R2(KΩ)");
            ItemDictionary.Add("D06", "电容(uF)");
            ItemDictionary.Add("D21", "电容(%)");
            ItemDictionary.Add("D2E", "R2(℃)");
            ItemDictionary.Add("D09", "放电电压(V)");
            ItemDictionary.Add("D32", "放电PACK电压(V)");
            ItemDictionary.Add("D33", "放电CELL电压(V)");
            ItemDictionary.Add("D34", "放电CELL-PACK(V)");
            ItemDictionary.Add("D0A", "放电电流(A)");
            ItemDictionary.Add("D0B", "直流阻抗(mΩ)");

            ItemDictionary.Add("D1E", "一级放电过流延时(ms)");

            ItemDictionary.Add("D0E", "放电过流延时(ms)");
            ItemDictionary.Add("D0F", "放电过流电流(A)");

            ItemDictionary.Add("D0C", "充电电压(V)");
            ItemDictionary.Add("D35", "充电PACK电压(V)");
            ItemDictionary.Add("D36", "充电CELL电压(V)");
            ItemDictionary.Add("D37", "充电PACK-CELL(V)");
            ItemDictionary.Add("D0D", "充电电流(A)");

            ItemDictionary.Add("D38", "一级过压下限");
            ItemDictionary.Add("D39", "一级过压下限电流");
            ItemDictionary.Add("D3A", "一级过压上限");
            ItemDictionary.Add("D3B", "一级过压上限电流");
            ItemDictionary.Add("D3C", "二级过压下限");
            ItemDictionary.Add("D3D", "二级过压下限电流");
            ItemDictionary.Add("D3E", "二级过压上限");
            ItemDictionary.Add("D3F", "二级过压上限电流");


            ItemDictionary.Add("D1F", "充电漏电流(uA)");
            ItemDictionary.Add("D20", "放电漏电流(uA)");

            ItemDictionary.Add("D10", "充电过流延时(ms)");
            ItemDictionary.Add("D11", "充电过流电流(A)");

            ItemDictionary.Add("D12", "短路保护延时(ms)");
            ItemDictionary.Add("D13", "短路后电压(V)");
            ItemDictionary.Add("D14", "短路恢复后电压(V)");
            ItemDictionary.Add("D2F", "短路前后压差(V)");
            ItemDictionary.Add("D22", "HDQ电压(V)");
            ItemDictionary.Add("D23", "SDA电压(V)");
            ItemDictionary.Add("D24", "SCL电压(V)");
            ItemDictionary.Add("D25", "V1 电压(V)");
            ItemDictionary.Add("D26", "CELL电压(V)");
            ItemDictionary.Add("D2C", "PACK电压(V)");
            ItemDictionary.Add("D2D", "CELL偏差(V)");
            ItemDictionary.Add("D27", "辅助电阻(KΩ)");
            ItemDictionary.Add("D28", "绝缘阻抗(MΩ)");
            ItemDictionary.Add("D29", "绝缘漏电(V)");
            ItemDictionary.Add("D01", "开路电压2(V)");
            ItemDictionary.Add("D2A", "开路压差(mV)");

            ItemDictionary.Add("P00", "BQ2022A Page1");
            ItemDictionary.Add("P01", "BQ2022A Page2");
            ItemDictionary.Add("P02", "BQ2022A Page3");
            ItemDictionary.Add("P03", "BQ2022A Page4");
            ItemDictionary.Add("P04", "BQ2022A Page5");
            ItemDictionary.Add("P05", "BQ2022A Page6");
            ItemDictionary.Add("P06", "BQ2022A Page7");
            ItemDictionary.Add("P07", "BQ2022A Page8");
            ItemDictionary.Add("PFF", "BQ2022A EPR ERR");
            ItemDictionary.Add("PF0", "BQ2022A家族码");
            ItemDictionary.Add("PF1", "BQ2022A ROM");

            ItemDictionary.Add("G00", "★CHIP ID");
            ItemDictionary.Add("G01", "★HW Version");
            ItemDictionary.Add("G02", "★FW Version");
            ItemDictionary.Add("G29", "★Chemistry ID");

            ItemDictionary.Add("G26", "★Chemistry Checksum");
            ItemDictionary.Add("G27", "★Static DF Checksum");
            ItemDictionary.Add("G28", "★All DF Checksum");
            ItemDictionary.Add("G05", "★测量温度");
            ItemDictionary.Add("G06", "★测量温度精度");

            ItemDictionary.Add("G09", "★开路实际电压");
            ItemDictionary.Add("G0A", "★开路测量电压");
            ItemDictionary.Add("G0B", "★开路测量电压精度");
            ItemDictionary.Add("G1C", "★开路电芯1电压");
            ItemDictionary.Add("G1D", "★开路电芯2电压");
            ItemDictionary.Add("G1E", "★开路电芯压差(mV)");
            ItemDictionary.Add("G3F", "★开路电流(mA)");

            ItemDictionary.Add("G0C", "★放电实际电流");
            ItemDictionary.Add("G0D", "★放电测量电流");
            ItemDictionary.Add("G0E", "★放电电流精度");
            ItemDictionary.Add("G22", "★放电电芯1电压");
            ItemDictionary.Add("G23", "★放电电芯2电压");
            ItemDictionary.Add("G24", "★放电电芯压差(mV)");

            ItemDictionary.Add("G0F", "★充电实际电流");
            ItemDictionary.Add("G10", "★充电测量电流");
            ItemDictionary.Add("G11", "★充电电流精度");
            ItemDictionary.Add("G1F", "★充电电芯1电压");
            ItemDictionary.Add("G20", "★充电电芯2电压");
            ItemDictionary.Add("G21", "★充电电芯压差(mV)");

            ItemDictionary.Add("G12", "★Design CAP.");
            ItemDictionary.Add("G43", "★Qmax Cell 0");
            ItemDictionary.Add("G46", "★Over Temp");
            ItemDictionary.Add("G2B", "★Nominal CAP.");
            ItemDictionary.Add("G2C", "★Full Available CAP.");
            ItemDictionary.Add("G14", "★Remainning CAP.");
            ItemDictionary.Add("G13", "★Full CHG CAP.");
            ItemDictionary.Add("G15", "★RelativeSOC");
            ItemDictionary.Add("G16", "★SOH");

            ItemDictionary.Add("G18", "★Cycle Count");

            ItemDictionary.Add("G17", "★Standby Current");
            ItemDictionary.Add("G2D", "★MaxLoad Current");

            ItemDictionary.Add("G31", "★Lifetime MaxTemp");
            ItemDictionary.Add("G32", "★Lifetime MinTemp");
            ItemDictionary.Add("G33", "★Lifetime MaxPackVoltage");
            ItemDictionary.Add("G34", "★Lifetime MinPackVoltage");
            ItemDictionary.Add("G35", "★Lifetime MaxChgCurrent");
            ItemDictionary.Add("G36", "★Lifetime MaxDsgCurrent");

            ItemDictionary.Add("G30", "★Pack Config");

            ItemDictionary.Add("G2E", "★BTPSOC1 Set");
            ItemDictionary.Add("G2F", "★BTPSOC1 Clear");
            ItemDictionary.Add("G40", "★Parameter Revision");

            ItemDictionary.Add("G44", "★Sleep Current");
            ItemDictionary.Add("G45", "★Terminate Voltage");
            ItemDictionary.Add("G4B", "★Charging Voltage");
            ItemDictionary.Add("G4C", "★Taper Current");
            ItemDictionary.Add("G4D", "★Min Taper Capacity");
            ItemDictionary.Add("G4E", "★Taper Voltage");
            ItemDictionary.Add("G4F", "★Current Taper Window");
            ItemDictionary.Add("G50", "★TCA Set");
            ItemDictionary.Add("G51", "★TCA Clear");
            ItemDictionary.Add("G52", "★FC Set");
            ItemDictionary.Add("G53", "★FC Clear");
            ItemDictionary.Add("G55", "★Sleep CHG");

            ItemDictionary.Add("G19", "★Control Status 1");
            ItemDictionary.Add("G49", "★Flags 1");

            ItemDictionary.Add("G1A", "★Control Status 2");
            ItemDictionary.Add("G4A", "★Flags 2");

            ItemDictionary.Add("G03", "★SEAL");
            ItemDictionary.Add("G1B", "★IT Enable");

            ItemDictionary.Add("G2A", "★SLEEP");

            ItemDictionary.Add("G41", "★Reset");

            ItemDictionary.Add("G25", "★Shutdown");

            ItemDictionary.Add("G80", "★Dataflash Comparge");

            ItemDictionary.Add("G81", "★Write Manuf. Data");
            ItemDictionary.Add("G90", "★PCM SN");
            ItemDictionary.Add("G91", "★PACK SN");
            ItemDictionary.Add("G92", "★Manufacturer Info A");
            ItemDictionary.Add("G93", "★Manufacturer Info B");
#if DESAY
                        ItemDictionary.Add("G42", "★I2C Config");
#endif
            ItemDictionary.Add("G82", "★MAX17050 Config");
            ItemDictionary.Add("G85", "★MAX17050 SUDNTimer");
            ItemDictionary.Add("G83", "★MAX17050 TGain");
            ItemDictionary.Add("G84", "★MAX17050 TOffset");

            #endregion

            Testpad.BTS.MemoryMapped.EventReceived += MemoryMapped_EventReceived;
            Testpad.BTS.MemoryMapped.ParameterReceived += MemoryMapped_ParameterReceived;
            //Testpad.BTS.MemoryMapped.DataReceived += MemoryMapped_DataReceived;
            Testpad.BTS.MemoryMapped.QueueEnable = true;//使不使用队列
            Testpad.BTS.MemoryMapped.SetVersion(0x80000000);
            #region ReadThread

#if !START_AND_READ_BY_BARCODE
            for (int Channel = 1; Channel <= CHANNEL_MAX; Channel++)
            {
                Thread ReadThread = new Thread(new ParameterizedThreadStart(Reading));
                ReadThread.IsBackground = true;//后台线程，软件关闭时自动销毁，没毛病
                ReadThread.Name = string.Format("ReadThread {0}", Channel);//线程名字，可省
                ReadThread.Start(Channel);
            } 
#endif

            #endregion

            //打开刷新定时器
            T_Status.Enabled = true;


            //System.Threading.Tasks.Task.Factory.StartNew(new Action(Event_Monitor));
        }

        private void MemoryMapped_EventReceived(Testpad.BTS.Event evt)
        {
            //事件模式下,GetEvent无效
            Console.WriteLine("{0}:{1}", evt.Channel, evt.Index);
            foreach(var s in evt.Messages)
            {
                Console.Write(s + ",");
            }
            Console.WriteLine("");

           switch (evt.Index)
            {
                case (int)MMF_EVENT_ID.ERROR:
                    {

                        break;
                    }
                case (int)MMF_EVENT_ID.BAT_REMOVED:
                    {

                        break;
                    }
            }
        }

        private void MemoryMapped_DataReceived(int arg1, List<Testpad.BTS.DataListItem> arg2)
        {
            //事件模式下,Pick无效,而且必须使用队列(Testpad.BTS.MemoryMapped.QueueEnable = true)

        }

        private void MemoryMapped_ParameterReceived(string ParameterXmlString)
        {
            //参数有个SHA256属性,它是XML根节点的InnerText的SHA256校验值
            Display(txtChannel1, ParameterXmlString);

        }

        #endregion

        #region ItemDictionary

        /// <summary>
        /// 用于映射简码和数据名称的字典
        /// </summary>
        private Dictionary<string, string> ItemDictionary = new Dictionary<string, string>();

        /// <summary>
        /// 从字典中查找简码对应的名称
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private string GetItemName(string key)
        {
            if (ItemDictionary.ContainsKey(key))
            {
                return ItemDictionary[key];
            }
            return key;
        }

        #endregion

        #region Display

        private void Display(TextBox txt, string Content)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<TextBox, string>(Display), txt, Content);
            }
            else
            {
                txt.Clear();
                txt.AppendText(Content +DateTime.Now.Ticks.ToString() + "\r\n");
            }
        }

        #endregion

        #region Timer

        private void T_Status_Tick(object sender, EventArgs e)
        {
            bool IsRunning;

            //指示BTS.EXE是否正在运行
            IsRunning = Testpad.BTS.MemoryMapped.BTS_IsRunning;
            if (IsRunning)
            {
                this.Text = "BTS内存共享例子(BTS运行中...)";
            }
            else
            {
                this.Text = "BTS内存共享例子(BTS未运行)";
            }
        }

        #endregion

        #region START_AND_READ_BY_BARCODE

#if START_AND_READ_BY_BARCODE

        private void BeginRead(int Channel, int Timeout)
        {
            IAsyncResult IAsync;
            Action<int, int> Op = new Action<int, int>(EndRead);
            IAsync = Op.BeginInvoke(Channel, Timeout, null, null);
        }

        private void EndRead(int Channel, int Timeout)
        {
            List<Testpad.BTS.DataListItem> DataList;
            bool DataIsReady = Testpad.BTS.MemoryMapped.Pick(Channel, Timeout, out DataList);
            if ((DataIsReady) && (DataList != null))
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("数据更新于:{0:yyyy/MM/dd HH:mm:ss}\r\n", DateTime.Now);
                foreach (var v in DataList)
                {
                    // string DataName = v.Name;
                    //可以调用DataName=GetItemName(v.Key)转换成自定义名称,也可使用默认名称
                    string DataName = GetItemName(v.Key);
                    sb.AppendFormat("项目[{0}]:{1},值:{2},标志:{3}\r\n", v.Key, DataName, v.Value, v.Flag);
                }

                switch (Channel)
                {
                    case 1:
                        {
                            Display(txtChannel1, sb.ToString());
                            break;
                        }
                    case 2:
                        {
                            Display(txtChannel2, sb.ToString());
                            break;
                        }
                }
            }
            else
            {
                switch (Channel)
                {
                    case 1:
                        {
                            Display(txtChannel1, "Timeout");
                            break;
                        }
                    case 2:
                        {
                            Display(txtChannel2, "Timeout");
                            break;
                        }
                }
            }
        }

#endif 

        #endregion

        #region ReadThread
        
        #if !START_AND_READ_BY_BARCODE
        private void Reading(object n)
        {

            int? Channel = n as int?;
            if(Channel!=null)
            {

                List<Testpad.BTS.DataListItem> DataList;
                while (true)
                {
                    #region 自动读回所有通道数据

                    bool DataIsReady = Testpad.BTS.MemoryMapped.Pick((int)Channel, 30000, out DataList);
                    if ((DataIsReady) && (DataList != null))
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendFormat("数据更新于:{0:yyyy/MM/dd HH:mm:ss}\r\n", DateTime.Now);
                        foreach (var v in DataList)
                        {
                            // string DataName = v.Name;
                            //可以调用DataName=GetItemName(v.Key)转换成自定义名称,也可使用默认名称
                            string DataName = GetItemName(v.Key);
                            sb.AppendFormat("项目[{0}]:{1},值:{2},标志:{3}\r\n", v.Key, DataName, v.Value, v.Flag);
                        }
                        switch (Channel)
                        {
                            case 1:
                                {
                                    Display(txtChannel1, sb.ToString());
                                    break;
                                }
                            case 2:
                                {
                                    Display(txtChannel2, sb.ToString());
                                    break;
                                }
                        }
                    }

                    #endregion

                    Thread.Sleep(1);
                }
            }
        }
        #endif

        #endregion

        #region Send Barcode

        private void btnSendBarcode_Click(object sender, EventArgs e)
        {
            if(numChannel.Value==1)
            {
                txtChannel1.Clear();
            }
            else
            {
                txtChannel2.Clear();
            }
            //将条码发送到指定通道号
            Testpad.BTS.MemoryMapped.SendBarcode((int)numChannel.Value, txtBarcode.Text);
#if START_AND_READ_BY_BARCODE
            BeginRead((int)numChannel.Value,5000);//必须根据实际测试情况去设置这个超时时间,因为不同的测试步骤所需要的时间是完全不同的
#endif
        }

        #endregion

        #region Send Parameter

        private void btnSendParameter_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "*.xml|*.xml";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                FileInfo fInfo = new FileInfo(dlg.FileName);
                using (StreamReader sr = fInfo.OpenText())
                {
                    string content = sr.ReadToEnd();
                    if (string.IsNullOrEmpty(content) == false)
                    {
                        Testpad.BTS.MemoryMapped.SendParameter(content,true);//修改参数不下载
                        //Testpad.BTS.MemoryMapped.SendParameter(content,false);//下载参数不修改
                    }
                }
            }
        }

        #endregion

        #region SendMessage

        private void btnSendMessage_Click(object sender, EventArgs e)
        {
            Testpad.BTS.MemoryMapped.SendMessage(1, 0x80000001, "1");
        }

        #endregion

        #region Read Event


        private void Event_Monitor()
        {
            //事件模式下,GetEvent无效
            while (true)
            {
                Thread.Sleep(10);

                for(int i=1;i<3;i++)
                {
                    Testpad.BTS.Event evt;

                    if(Testpad.BTS.MemoryMapped.GetEvent(i, 10,out evt))
                    {
                        StringBuilder sb = new StringBuilder();
                        TextBox txt;

                        if (i == 1)
                        {
                            txt = txtChannel1;
                        }
                        else
                        {
                            txt = txtChannel2;
                        }

                        sb.AppendFormat("Event Index:{0}\r\n",evt.Index.ToString());
                        foreach(string s in evt.Messages)
                        {
                            sb.AppendFormat("Message:{0}\r\n",s);
                        }
                        sb.Append("***********\r\n");

                        Display(txt, sb.ToString());
                    }
                }
            }
        }

        #endregion

        #region 用定时器读取测试结果

        //private void T_Read_Tick(object sender, EventArgs e)
        //{
        //    T_Read.Enable = false;

        //    List<Testpad.BTS.DataListItem> DataList;
        //    bool DataIsReady = Testpad.BTS.MemoryMapped.Pick(1, 10, out DataList);
        //    if ((DataIsReady) && (DataList != null))
        //    {
        //        StringBuilder sb = new StringBuilder();
        //        sb.AppendFormat("数据更新于:{0:yyyy/MM/dd HH:mm:ss}\r\n", DateTime.Now);
        //        foreach (var v in DataList)
        //        {
        //            // string DataName = v.Name;
        //            //可以调用DataName=GetItemName(v.Key)转换成自定义名称,也可使用默认名称
        //            string DataName = GetItemName(v.Key);
        //            sb.AppendFormat("项目[{0}]:{1},值:{2},标志:{3}\r\n", v.Key, DataName, v.Value, v.Flag);
        //        }

        //        Display(txtChannel1, sb.ToString());
        //    }

        //    T_Read.Enable = true;
        //} 

        #endregion

    }
}
